package com.example.pc.videodemo

import android.media.AudioFormat
import android.media.AudioRecord
import java.io.*


/**
 *  @author: hyzhan
 *  @date:   2019/7/1
 *  @desc:   TODO
 */
class FileUtils(private val mSampleRate: Int, private val mChannel: Int, encoding: Int) {

    private val mBufferSize by lazy { AudioRecord.getMinBufferSize(mSampleRate, mChannel, encoding) }

    /**
     * pcm文件转wav文件
     *
     * @param inFilename 源文件路径
     * @param outFilename 目标文件路径
     */
    fun pcmToWav(inFilename: String, outFilename: String) {
        val input: FileInputStream
        val out: FileOutputStream
        val totalAudioLen: Long
        val totalDataLen: Long
        val longSampleRate = mSampleRate.toLong()
        val channels = if (mChannel == AudioFormat.CHANNEL_IN_MONO) 1 else 2
        val byteRate = (16 * mSampleRate * channels / 8).toLong()
        val data = ByteArray(mBufferSize)
        try {
            input = FileInputStream(inFilename)
            out = FileOutputStream(outFilename)
            totalAudioLen = input.channel.size()

            "totalAudioLen = $totalAudioLen".showLog()

            totalDataLen = totalAudioLen + 36

            "totalDataLen = $totalDataLen".showLog()

            writeWaveFileHeader(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate)
            while (input.read(data) != -1) {
                out.write(data)
            }

            input.close()
            out.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }


    /**
     * 加入wav文件头
     */
    private fun writeWaveFileHeader(out: FileOutputStream, totalAudioLen: Long,
                                    totalDataLen: Long, longSampleRate: Long, channels: Int, byteRate: Long) {
        val header = ByteArray(44)
        // RIFF/WAVE header
        header[0] = 'R'.toByte()
        header[1] = 'I'.toByte()
        header[2] = 'F'.toByte()
        header[3] = 'F'.toByte()
        header[4] = (totalDataLen and 0xff).toByte()
        header[5] = (totalDataLen shr 8 and 0xff).toByte()
        header[6] = (totalDataLen shr 16 and 0xff).toByte()
        header[7] = (totalDataLen shr 24 and 0xff).toByte()
        //WAVE
        header[8] = 'W'.toByte()
        header[9] = 'A'.toByte()
        header[10] = 'V'.toByte()
        header[11] = 'E'.toByte()
        // 'fmt ' chunk
        header[12] = 'f'.toByte()
        header[13] = 'm'.toByte()
        header[14] = 't'.toByte()
        header[15] = ' '.toByte()
        // 4 bytes: size of 'fmt ' chunk
        header[16] = 16
        header[17] = 0
        header[18] = 0
        header[19] = 0
        // format = 1
        header[20] = 1
        header[21] = 0
        header[22] = channels.toByte()
        header[23] = 0
        header[24] = (longSampleRate and 0xff).toByte()
        header[25] = (longSampleRate shr 8 and 0xff).toByte()
        header[26] = (longSampleRate shr 16 and 0xff).toByte()
        header[27] = (longSampleRate shr 24 and 0xff).toByte()
        header[28] = (byteRate and 0xff).toByte()
        header[29] = (byteRate shr 8 and 0xff).toByte()
        header[30] = (byteRate shr 16 and 0xff).toByte()
        header[31] = (byteRate shr 24 and 0xff).toByte()
        // block align
        header[32] = (2 * 16 / 8).toByte()
        header[33] = 0
        // bits per sample
        header[34] = 16
        header[35] = 0
        //data
        header[36] = 'd'.toByte()
        header[37] = 'a'.toByte()
        header[38] = 't'.toByte()
        header[39] = 'a'.toByte()
        header[40] = (totalAudioLen and 0xff).toByte()
        header[41] = (totalAudioLen shr 8 and 0xff).toByte()
        header[42] = (totalAudioLen shr 16 and 0xff).toByte()
        header[43] = (totalAudioLen shr 24 and 0xff).toByte()
        out.write(header, 0, 44)
    }

    fun pcm2wav(data: ByteArray): ByteArray{

//        val result = ByteArray(44 + data.size)

        val sampleRate = 8000
        val channels = 1
        val byteRate = (16 * sampleRate * channels / 8).toLong()

        val totalAudioLen = data.size
        val totalDataLen = totalAudioLen + 36


        val header = ByteArray(44 + data.size)
        // RIFF/WAVE header
        header[0] = 'R'.toByte()
        header[1] = 'I'.toByte()
        header[2] = 'F'.toByte()
        header[3] = 'F'.toByte()
        header[4] = (totalDataLen and 0xff).toByte()
        header[5] = (totalDataLen shr 8 and 0xff).toByte()
        header[6] = (totalDataLen shr 16 and 0xff).toByte()
        header[7] = (totalDataLen shr 24 and 0xff).toByte()
        //WAVE
        header[8] = 'W'.toByte()
        header[9] = 'A'.toByte()
        header[10] = 'V'.toByte()
        header[11] = 'E'.toByte()
        // 'fmt ' chunk
        header[12] = 'f'.toByte()
        header[13] = 'm'.toByte()
        header[14] = 't'.toByte()
        header[15] = ' '.toByte()
        // 4 bytes: size of 'fmt ' chunk
        header[16] = 16
        header[17] = 0
        header[18] = 0
        header[19] = 0
        // format = 1
        header[20] = 1
        header[21] = 0
        header[22] = channels.toByte()
        header[23] = 0
        header[24] = (sampleRate and 0xff).toByte()
        header[25] = (sampleRate shr 8 and 0xff).toByte()
        header[26] = (sampleRate shr 16 and 0xff).toByte()
        header[27] = (sampleRate shr 24 and 0xff).toByte()
        header[28] = (byteRate and 0xff).toByte()
        header[29] = (byteRate shr 8 and 0xff).toByte()
        header[30] = (byteRate shr 16 and 0xff).toByte()
        header[31] = (byteRate shr 24 and 0xff).toByte()
        // block align
        header[32] = (2 * 16 / 8).toByte()
        header[33] = 0
        // bits per sample
        header[34] = 16
        header[35] = 0
        //data
        header[36] = 'd'.toByte()
        header[37] = 'a'.toByte()
        header[38] = 't'.toByte()
        header[39] = 'a'.toByte()
        header[40] = (totalAudioLen and 0xff).toByte()
        header[41] = (totalAudioLen shr 8 and 0xff).toByte()
        header[42] = (totalAudioLen shr 16 and 0xff).toByte()
        header[43] = (totalAudioLen shr 24 and 0xff).toByte()

        // 添加原始数据
        data.forEachIndexed { index, byte ->
            header[44 + index] = byte
        }

        return header
    }

//    fun pcm2wav(data: ByteArray) {
//        var sampleRate = 8000    //采样率
//        var sampleBits = 16      //采样位数
//        var dataLength = data.size
//        var buffer = ArrayBuffer(44 + dataLength)
//        var data = DataView(buffer)    //可使用 DataView 对象在 ArrayBuffer 中的任何位置读取和写入不同类型的二进制数据。
//
//
//        var channelCount = 1//单声道
//        var offset = 0
//
//        var writeString = function(str) {
//            for (var i = 0; i < str.length; i++) {
//            data.setUint8(offset + i, str.charCodeAt(i))
//        }
//        };
//
//        // 资源交换文件标识符
//        writeString('RIFF');
//        offset += 4;
//        // 下个地址开始到文件尾总字节数,即文件大小-8
//        data.setUint32(offset, 36 + dataLength, true);
//        offset += 4;
//        // WAV文件标志
//        writeString('WAVE');
//        offset += 4;
//        // 波形格式标志
//        writeString('fmt ');
//        offset += 4;
//        // 过滤字节,一般为 0x10 = 16
//        data.setUint32(offset, 16, true);
//        offset += 4;
//        // 格式类别 (PCM形式采样数据)
//        data.setUint16(offset, 1, true);
//        offset += 2;
//        // 通道数
//        data.setUint16(offset, channelCount, true);
//        offset += 2;
//        // 采样率,每秒样本数,表示每个通道的播放速度
//        data.setUint32(offset, sampleRate, true);
//        offset += 4;
//        // 波形数据传输率 (每秒平均字节数) 单声道×每秒数据位数×每样本数据位/8
//        data.setUint32(offset, channelCount * sampleRate * (sampleBits / 8), true);
//        offset += 4;
//        // 快数据调整数 采样一次占用字节数 单声道×每样本的数据位数/8
//        data.setUint16(offset, channelCount * (sampleBits / 8), true);
//        offset += 2;
//        // 每样本数据位数
//        data.setUint16(offset, sampleBits, true);
//        offset += 2;
//        // 数据标识符
//        writeString('data');
//        offset += 4;
//        // 采样数据总数,即数据总大小-44
//        data.setUint32(offset, dataLength, true);
//        offset += 4;
//        //数据位
//        for (var i = 0; i < data.length; i++, offset++) {
//            data.setUint8(offset, data[i]);
//        }
//
//        // 写入采样数据
//
//        return buffer
//    }
}